package mapreduce;

import java.nio.ByteBuffer;
import java.util.Vector;

public class MultipleTypeFormat extends BytesFormat {

	public MultipleTypeFormat(){
		
	}
	
	public MultipleTypeFormat(BytesFormat[] formats){
		for(int i = 0 ; i < formats.length; i ++){
			m_formats.add(formats[i]);
		}
	}
	
	public BytesFormat getFormat(){
		return new MultipleTypeFormat();
	}
	
	public int size() {
		return m_formats.size();
	}

	public void addFormat(BytesFormat format) {
		m_formats.add(format);
	}

	protected byte[] format(Object object) {
		Object[] objs = (Object[]) object;
		Vector<byte[]> outBytesVec = new Vector<byte[]>();
		int typeNum = objs.length;
		int byteNum = 0;
		for (int i = 0; i < typeNum; i++) {
			byte[] outBytes = m_formats.elementAt(i).format(objs[i]);
			outBytesVec.add(outBytes);
			byteNum += outBytes.length;
		}
		ByteBuffer outBuffer = ByteBuffer.allocate(byteNum + typeNum);
		for (int i = 0; i < typeNum; i++) {
			byte[] bytes = outBytesVec.elementAt(i);
			outBuffer.put(bytes);
			outBuffer.put((byte) ';');
		}
		return outBuffer.array();
	}

	Vector<BytesFormat> m_formats = new Vector<BytesFormat>();

	@Override
	public Object decode(ByteBuffer buffer) {
		Vector<Object> objVec = new Vector<Object>();
		while (true) {
			int code = buffer.getInt();
			BytesFormat format = BytesFormat.getFormt(code);
			this.addFormat(format);
			objVec.add(format.decode(buffer));
			if (buffer.position() >= buffer.limit()) {
				break;
			}
		}
		return objVec.toArray();
	}

	@Override
	public ByteBuffer encode(Object object, ByteBuffer buffer) {
		Object[] objects = (Object[]) object;
		int objectNum = objects.length;
		for (int i = 0; i < objectNum; i++) {
			BytesFormat format = m_formats.elementAt(i);
			buffer = BufferChecker.check(buffer, 4);
			buffer.putInt(format.getCode());
			buffer = format.encode(objects[i], buffer);
		}
		return buffer;
	}

	public boolean equals(Object anotherObject) {
		if (this.getClass() != anotherObject.getClass()) {
			return false;
		}
		MultipleTypeFormat anotherFormat = (MultipleTypeFormat) anotherObject;
		if(size() != anotherFormat.size()){
			return false;
		}
		int subFormatNum = size();
		for(int i = 0 ; i < subFormatNum; i ++){
			if(! m_formats.elementAt(i).equals(anotherFormat.getSubFormat(i))){
				return false;
			}
		}
		return true;
	}

	public BytesFormat getSubFormat(int i) {
		return m_formats.elementAt(i);
	}

	@Override
	protected int getCode() {
		// TODO Auto-generated method stub
		return 11;
	}

}
